<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <title>视频转GIF工具</title>
    <style>
      .title {
        text-align: center;
      }
      .container {
        max-width: 800px;
        margin: 20px auto;
        padding: 20px;
      }
      #preview {
        border: 2px dashed #ccc;
        margin: 10px 0;
      }
      .loading {
        display: none;
        color: #666;
      }
    </style>
  </head>
  <body>
    <h1 class="title">视频转GIF工具</h1>
    <p>截取长度不要超过30s，否则很有可能转换失败甚至是浏览器卡死，尽量将时间控制短一些</p>
    <div class="container">
      <input type="file" id="videoInput" accept="video/*" />
      <div id="preview">
        <video id="video" width="100%" controls></video>
      </div>

      <div>
        <label>开始时间：<input type="number" id="startTime" value="0" step="0.1" /></label>
        <label>结束时间：<input type="number" id="endTime" value="5" step="0.1" /></label>
        <button id="convertBtn">开始转换</button>
        <span class="loading">转换中... (请勿刷新页面)</span>
      </div>

      <div id="output" style="margin-top: 20px"></div>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/gif.js/0.2.0/gif.js"></script>
    <script>
      let videoDuration = 0;

      // 视频加载处理
      document.getElementById("videoInput").addEventListener("change", function (e) {
        const file = e.target.files[0];
        if (!file) return;

        const video = document.getElementById("video");
        const videoURL = URL.createObjectURL(file);

        video.src = videoURL;
        video.addEventListener("loadedmetadata", () => {
          videoDuration = video.duration;
          document.getElementById("endTime").max = videoDuration.toFixed(1);
          document.getElementById("endTime").value = Math.min(5, videoDuration).toFixed(1);
        });
      });

      // 转换核心逻辑
      document.getElementById("convertBtn").addEventListener("click", async () => {
        const video = document.getElementById("video");
        if (!video.src) return alert("请先上传视频文件");

        // 参数校验
        const startTime = parseFloat(document.getElementById("startTime").value);
        const endTime = parseFloat(document.getElementById("endTime").value);
        if (startTime >= endTime) return alert("开始时间必须小于结束时间");
        if (endTime > videoDuration) return alert("结束时间超过视频时长");

        // 初始化GIF生成器
        const gif = new GIF({
          workers: 4,
          quality: 10,
          width: video.videoWidth,
          height: video.videoHeight,
          workerScript: "./gif.worker.js",
          willReadFrequently: true,
        });

        // 显示加载状态
        document.querySelector(".loading").style.display = "inline";

        try {
          // 创建画布
          const canvas = document.createElement("canvas");
          canvas.width = video.videoWidth;
          canvas.height = video.videoHeight;
          const ctx = canvas.getContext("2d");

          // 设置初始时间
          video.currentTime = startTime;

          // 等待视频定位
          await new Promise((resolve) => video.addEventListener("seeked", resolve, { once: true }));

          // 帧捕获逻辑
          const captureFrames = () => {
            return new Promise((resolve) => {
              const interval = 250; // 每250ms捕获一帧
              let currentTime = startTime;

              const timer = setInterval(() => {
                if (currentTime >= endTime) {
                  clearInterval(timer);
                  gif.render();
                  resolve();
                  return;
                }

                ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
                gif.addFrame(ctx.getImageData(0, 0, canvas.width, canvas.height), { delay: interval });

                currentTime += interval / 1000;
                video.currentTime = currentTime;
              }, interval);
            });
          };

          await captureFrames();

          // GIF生成完成
          gif.on("finished", (blob) => {
            const downloadLink = document.createElement("a");
            downloadLink.download = `output_${Date.now()}.gif`;
            downloadLink.href = URL.createObjectURL(blob);
            downloadLink.textContent = "下载GIF文件";
            document.getElementById("output").innerHTML = "";
            document.getElementById("output").appendChild(downloadLink);
            document.querySelector(".loading").style.display = "none";
          });
        } catch (error) {
          console.error(" 转换失败:", error);
          alert("转换失败，请检查控制台");
          document.querySelector(".loading").style.display = "none";
        }
      });
    </script>
  </body>
</html>
